From 8da2f6c59c1e310a67c7867ff7a6bb464b239a50 Mon Sep 17 00:00:00 2001 From: "kaf24@localhost.localdomain" Date: Sat, 19 Aug 2006 11:08:40 +0100 Subject: [PATCH] [NET] front: Fix tx buffer leak in teardown path. Fix rx-buffer cleanup: cannot free skbuffs until their memory is remapped by multicall. Signed-off-by: Keir Fraser --- .../drivers/xen/netfront/netfront.c | 43 +++++++++++++------ 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c index 039a2a6bcb..5625caa9af 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c @@ -1397,10 +1397,31 @@ err: return more_to_do; } +static void netif_release_tx_bufs(struct netfront_info *np) +{ + struct sk_buff *skb; + int i; + + for (i = 1; i <= NET_TX_RING_SIZE; i++) { + if ((unsigned long)np->tx_skbs[i] < PAGE_OFFSET) + continue; + + skb = np->tx_skbs[i]; + gnttab_end_foreign_access_ref( + np->grant_tx_ref[i], GNTMAP_readonly); + gnttab_release_grant_reference( + &np->gref_tx_head, np->grant_tx_ref[i]); + np->grant_tx_ref[i] = GRANT_INVALID_REF; + add_id_to_freelist(np->tx_skbs, i); + dev_kfree_skb_irq(skb); + } +} + static void netif_release_rx_bufs(struct netfront_info *np) { struct mmu_update *mmu = np->rx_mmu; struct multicall_entry *mcl = np->rx_mcl; + struct sk_buff_head free_list; struct sk_buff *skb; unsigned long mfn; int xfer = 0, noxfer = 0, unused = 0; @@ -1411,6 +1432,8 @@ static void netif_release_rx_bufs(struct netfront_info *np) return; } + skb_queue_head_init(&free_list); + spin_lock(&np->rx_lock); for (id = 0; id < NET_RX_RING_SIZE; id++) { @@ -1451,7 +1474,7 @@ static void netif_release_rx_bufs(struct netfront_info *np) set_phys_to_machine(pfn, mfn); } - dev_kfree_skb(skb); + __skb_queue_tail(&free_list, skb); xfer++; } @@ -1474,6 +1497,9 @@ static void netif_release_rx_bufs(struct netfront_info *np) } } + while ((skb = __skb_dequeue(&free_list)) != NULL) + dev_kfree_skb(skb); + spin_unlock(&np->rx_lock); } @@ -1573,19 +1599,7 @@ static void network_connect(struct net_device *dev) */ /* Step 1: Discard all pending TX packet fragments. */ - for (requeue_idx = 0, i = 1; i <= NET_TX_RING_SIZE; i++) { - if ((unsigned long)np->tx_skbs[i] < PAGE_OFFSET) - continue; - - skb = np->tx_skbs[i]; - gnttab_end_foreign_access_ref( - np->grant_tx_ref[i], GNTMAP_readonly); - gnttab_release_grant_reference( - &np->gref_tx_head, np->grant_tx_ref[i]); - np->grant_tx_ref[i] = GRANT_INVALID_REF; - add_id_to_freelist(np->tx_skbs, i); - dev_kfree_skb_irq(skb); - } + netif_release_tx_bufs(np); /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */ for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) { @@ -1632,6 +1646,7 @@ static void network_connect(struct net_device *dev) static void netif_uninit(struct net_device *dev) { struct netfront_info *np = netdev_priv(dev); + netif_release_tx_bufs(np); netif_release_rx_bufs(np); gnttab_free_grant_references(np->gref_tx_head); gnttab_free_grant_references(np->gref_rx_head); -- 2.30.2